iT邦幫忙

2023 iThome 鐵人賽

DAY 23
0
Security

從自建漏洞中學習 - 一起填坑吧系列 第 23

Auth 應用程式 - Error 處理篇之 3

  • 分享至 

  • xImage
  •  

Auth 應用程式 - Error 處理篇之 3

接下來我們今天來介紹不同環境下要如何處理 Error 以及我們需要處裡哪些 Error :

不同環境 - Development & Staging / Production

https://ithelp.ithome.com.tw/upload/images/20231008/20107197IFoSMHvPpB.png

  • 在 Development 環境中:

    盡可能方便我們追蹤錯誤,所以會傾向 Error message 越詳細越好。

    例如: 可以知道是哪個地方發生錯誤,路徑是什麼?

    範例:

    const sendDevelopmentError = (err, res) => {
        res.status(err.statusCode).json({
            status: err.status,
            error: err,
            message: err.message,
            stack: err.stack
        })
    } 
    

    解說:

    可以看到在以上範例,我們沒有傳送 error & stack。

  • 在 Staging / Production 環境中:

    1. 不要向客戶端傳太過複雜的 Error Message,盡量易懂
    2. 不要向客戶端傳送詳細的發生錯誤路徑或是實際程式碼發生的詳細錯誤,這會讓 hacker 更容易追蹤

    範例:

    const sendProdctionError = (err, res) => {
        // 如果是操作型的 Error,傳送他
        if (err.isOperational) {
            res.status(err.statusCode).json({
                status: err.status,
                message: err.message
            })
        } else {
            // log error         
            console.error('Error: ', err);
    
            // 若非操作型 Error,傳送比較 general 的 error message
            res.status(500).json({
                status: 'error',
                message: 'Something went wrong'
            })
        }
        res.status(err.statusCode).json({
            status: err.status,
            message: err.message,
        })
    } 
    

    解說:

    可以看到在以上範例,我們沒有傳送 error & stack。

  • 最後,在 ErrorController 中判斷 env development or production:

    module.exports = (err, req, res, next) => {
    
        err.statusCode = err.statusCode || 500;
        err.status = err.status || 'error';
    
        if (process.env.NODE_ENV === 'development') {
            sendDevelopmentError(err, res);
        } else if (process.env.NODE_ENV === 'prodcution') {
            sendProductionError(err, res);
        }
    
    }
    

有哪些需要考慮的 Error 種類?

還記得我們之前介紹的 Error 種類大致分為哪幾種嗎?

https://ithelp.ithome.com.tw/upload/images/20231008/20107197UinWXs2t5i.png

有 Operational Error 以及 Programming Error。

思考哪些 Error 有在我們的 Operational Error 範疇 ?

在處理 Operational Error 時,需要考慮我們自己處理了哪些 Operational Error ? 而哪些 Operational Error 目前是沒有被標記成 Operational 的呢 ?

在此處,除了有關沒有資料的 Error 外,我們還需要考慮與 "資料庫" 相關的 Error ~

我們是使用 MongoDB ,MongoDB 有很多種不同的 Error,可以參考:

https://ithelp.ithome.com.tw/upload/images/20231008/20107197heVlUus2Ps.png

(圖片來源: https://mongoosejs.com/docs/5.x/docs/api/error.html)

可以根據自己的需求,去處理有關的 Error:

假設我們要處理 CastError:

範例:

const handleCastErrorInDB = err => {
    const message = `Invalid ${err.path} : ${err.value}`;
    // 400 意味著錯誤請求
    return new AppError(message, 400);
}

在先前判斷環境的入口,我們可以加上以下 error 來處理 DB 的 CastError:

let error = { ...err };

if (error.name === 'CastError') error = handleCastErrorInDB(error);

Unhandled Rejection & Uncaught Exceptions

Uncaught Exceptions

在同步的程式中,可能會出現 Uncaught Exception,例如: 一些 Programming Error,像是在某處讀取了 undefined 的元素。

在 Node.js 中,它在 process 中就會捕獲發現的 uncaught Exception,所以我們可以透過監聽他並進行處理:

process.on('uncaughtException', err => {
    console.log(err.name, err.message);
    console.log('Unhandled Exception and we need to shut down.');
    server.close(() => {
        process.exit(1);
    })
});

Unhandled Rejection

非同步程式碼中,也可能會出現一些我們之前沒有處理過的例外狀況,例如: MongoDB 不能連線。

在 Node.js 中,它在 process 中就會捕獲發現的 unhandled Rejection,所以我們可以透過監聽他並進行處理:

process.on('unhandledRejection', err => {
    console.log(err.name, err.message);
    console.log('Unhandled Rejection and we need to shut down.');
    server.close(() => {
        process.exit(1);
    })
});

今日小心得

今天的介紹就到這邊啦 ~ 明天會繼續進行其他的介紹


Reference:


上一篇
Auth 應用程式 - Error 處理篇之 2
下一篇
Auth 應用程式 - Authentication 認證篇 2 - 加入 Error 處理
系列文
從自建漏洞中學習 - 一起填坑吧30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言